#include "Camera.h"



Camera::Camera(GLMatrixStack *pMVM)
{
	this->pMVM=pMVM;
	//rot=-0.06f;
	camMx = new M3DMatrix44f[1];
	camMode = 99;
}
void Camera::pushMatrix(bool sky){
	if(sky){								//if the call is for skybox only
		pMVM->PushMatrix();
		cam.GetCameraMatrix(camMx[0],true);
		pMVM->LoadMatrix(camMx[0]);
	}else{
		cam.GetCameraMatrix(camMx[0]);
		pMVM->PushMatrix(camMx[0]);
	}
}
void Camera::popcam(){
	pMVM->PopMatrix();
}
void Camera::update(float*ppos,float*pang){
	cam.SetOrigin(ppos);
	cam.SetForwardVector(pang);
	
	//cam.RotateLocalY(this->rot);
	//cam.MoveForward(-5.9f);
	//cam.MoveUp(0.35f);
	//cam.MoveRight(0.5f);
}
void Camera::update(Vector3f pos, Vector3f tgt){
	Vector3f AB;
	M3DVector3f v;
	//static bool camReset = false;

	switch(camMode){
	
	case 0:
		cam.SetOrigin(pos.x,pos.y,pos.z);
		//get Lookat vector.
		cam.MoveForward(-10.0f);
		cam.MoveUp(1.0f);
		cam.MoveRight(1.0f);
		cam.GetOrigin(v);
		pos.x=v[0];
		pos.y=v[1];
		pos.z=v[2];
	
		AB = tgt - pos;
		AB.y = 0.0f;
		AB.normalizeMe();
		cam.SetForwardVector(AB.x, AB.y, AB.z);
		
		break;
	case 1:
		
		pos.x = -50.0f;
		pos.y = 0;
		pos.z = -1000.0f;
		cam.SetOrigin(pos.x,pos.y,pos.z);
		AB = tgt - pos;
		AB.y = 0.0f;
		AB.normalizeMe();
		cam.SetForwardVector(AB.x, AB.y, AB.z);

		break;
	case 2:
		//use tgt as vector to face toward.
		cam.SetOrigin(pos.x,pos.y,pos.z);
		if(!tgt.isZero()){
			tgt.normalizeMe();
		}else{
			tgt.x = -1.0f;
		}
		
		this->setForwardVector(tgt);
		cam.MoveRight(0.5);
		cam.MoveForward(0.5);

		break;

	case 99:
		cam.SetOrigin(pos.x,pos.y,pos.z);

		break;
	default:
		break;

	}
}
void Camera::setForwardVector(Vector3f v){
	
	//store right pointing vector. To use later.
	if(!v.isZero()){

		Vector3f u,f,r;
		M3DVector3f up,fwd,rt;
		cam.GetForwardVector(fwd);
		cam.GetUpVector(up);
				
		u.fromM3D(up);
		f.fromM3D(fwd);
		//right handed
		r = f.crossProduct(u);
		r.normalizeMe();
		//okay...
		f = v;
		f.normalizeMe();
		
		u = r.crossProduct(f);
		u.normalizeMe();
		f.toM3D(fwd);
		cam.SetForwardVector(fwd);
		u.toM3D(up);
		cam.SetUpVector(up);

	}

}
void Camera::changeMode(int mode){
	this->resetForwardVector();
	this->resetUpVector();
	camMode = mode;

	
}

int Camera::getMode(){
	return camMode;
}

void Camera::spin(){
	rot-=0.01f;
}
M3DMatrix44f *Camera::getMx(bool sky){
	if(sky){
		cam.GetCameraMatrix(camMx[0],true);
	}else{
		cam.GetCameraMatrix(camMx[0]);
	}
	return camMx;

}
Camera::~Camera(){
}


void Camera::moveForward()
{
	M3DVector3f temp;
	cam.GetForwardVector(temp);
	float x = cam.GetOriginX() + (temp[0] * 1);
	float y = cam.GetOriginY();
	float z = cam.GetOriginZ() + (temp[2] * 1);
	cam.SetOrigin(x,y,z);
}

// This function alows the camera to move along the worlds z axis regardless of the cameras own orientation
void Camera::moveBackward()
{
	M3DVector3f temp;
	cam.GetForwardVector(temp);
	float x = cam.GetOriginX() + (temp[0] * -1);
	float y = cam.GetOriginY();
	float z = cam.GetOriginZ() + (temp[2] * -1);
	cam.SetOrigin(x,y,z);
}